#include "bindings/bindings_helper.h"
#include "helpers/general.h"
#include "models/dimensions_helper.h"
#include "refs.h"
#include "rive/layout.hpp"
#include "rive/math/aabb.hpp"
#include "rive/math/mat2d.hpp"
#include "rive/math/vec2d.hpp"
#include <napi/native_api.h>

namespace ohos_rive {

static bool GetPointFromObject(napi_env env, napi_value obj, rive::Vec2D &point)
{
    napi_value xValue, yValue;

    if (napi_get_named_property(env, obj, "x", &xValue) != napi_ok)
        return false;
    if (napi_get_named_property(env, obj, "y", &yValue) != napi_ok)
        return false;

    double x, y;
    if (napi_get_value_double(env, xValue, &x) != napi_ok)
        return false;
    if (napi_get_value_double(env, yValue, &y) != napi_ok)
        return false;

    point = rive::Vec2D((float)x, (float)y);
    return true;
}

static napi_value CreatePointObject(napi_env env, rive::Vec2D &convertedLocation)
{
    napi_value resultPoint;
    if (napi_create_object(env, &resultPoint) != napi_ok)
        return nullptr;

    napi_value xValue, yValue;
    if (napi_create_double(env, convertedLocation.x, &xValue) != napi_ok)
        return nullptr;
    if (napi_create_double(env, convertedLocation.y, &yValue) != napi_ok)
        return nullptr;
    if (napi_set_named_property(env, resultPoint, "x", xValue) != napi_ok)
        return nullptr;
    if (napi_set_named_property(env, resultPoint, "y", yValue) != napi_ok)
        return nullptr;

    return resultPoint;
}

napi_value ConvertToArtboardSpace(napi_env env, napi_callback_info info)
{
    size_t argc = 6;
    napi_value args[6];
    auto status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    if (status != napi_ok) {
        return nullptr;
    }

    if (argc < 6) {
        LOGE("Invalid arguments, expected 6 arguments, actual number of arguments: %ld", argc);
        return nullptr;
    }

    napi_value touchSpaceRectF = args[0];
    napi_value touchSpacePointF = args[1];
    napi_value fitValue = args[2];
    napi_value alignmentValue = args[3];
    napi_value artboardSpaceRectF = args[4];

    double scaleFactor;
    status = napi_get_value_double(env, args[5], &scaleFactor);
    if (status != napi_ok) {
        return nullptr;
    }

    auto fit = GetFit(env, fitValue);
    auto alignment = GetAlignment(env, alignmentValue);
    auto artboardSpaceBounds = RectFToAABB(env, artboardSpaceRectF);
    auto touchSpaceBounds = RectFToAABB(env, touchSpaceRectF);

    rive::Vec2D touchLocation;
    if (!GetPointFromObject(env, touchSpacePointF, touchLocation)) {
        LOGE("Get touch point error");
        return nullptr;
    }

    rive::Mat2D forward = computeAlignment(fit, alignment, touchSpaceBounds, artboardSpaceBounds, (float)scaleFactor);
    rive::Mat2D inverse = forward.invertOrIdentity();

    rive::Vec2D convertedLocation = inverse * touchLocation;

    napi_value resultPoint = CreatePointObject(env, convertedLocation);
    if (resultPoint == nullptr) {
        LOGE("Create object error");
        return nullptr;
    }

    return resultPoint;
}
} // namespace ohos_rive
